﻿using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.IO;

namespace ImageProcessing.Service
{
    /// <summary>
    /// 图像处理库的互操作类。
    /// 提供对图像处理 DLL 的动态调用封装。
    /// </summary>
    public class CvLibInterop1 : IDisposable
    {
        private nint _dllHandle;

        // 单例实例
        private static CvLibInterop1 _instance;

        private static readonly object _lock = new object();

        // 委托声明
        public delegate nint InitImageDrHanderDelegate(string modelPath, int someInt);

        public delegate void CloseImageDrHandlerDelegate(nint handler);

        public delegate double SkewAngleDelegate(nint handler, string imagePath);

        public delegate nint DeskewingDelegate(nint handler, string inputImagePath, string outputImagePath);

        public delegate int TextImageOrientationDelegate(nint handler, string imagePath);

        public delegate void RotateDelegate(nint handler, string imagePath, int angle, string outputImagePath);

        public delegate nint CleanupDelegate(nint handler, string inputname, string outputname);

        public delegate nint RemoveBlackEdgesDelegate(string inputname, string outputname, double thresholdValue);

        public delegate nint SetToWhiteDelegate(string inputname, string outputname, int x, int y, int width, int height, int inside);

        public delegate nint ChangeGammaDelegate(string inputname, string outputname, double gammaValue);

        public delegate nint ChangeContrastAndBrightDelegate(string inputname, string outputname, double contrast, double brightValue);

        public delegate nint DeskewingWithAngleDelegate(nint handler, string inputname, double angle, string outputname);

        // 公共委托定义
        public InitImageDrHanderDelegate initImageDrHander;

        public CloseImageDrHandlerDelegate closeImageDrHandler;
        public SkewAngleDelegate skewAngle;
        public DeskewingDelegate deskewing;
        public TextImageOrientationDelegate textImageOrientation;
        public RotateDelegate rotate;
        public CleanupDelegate cleanup;
        public RemoveBlackEdgesDelegate removeBlackEdges;
        public SetToWhiteDelegate setToWhite;
        public ChangeGammaDelegate changeGamma;
        public ChangeContrastAndBrightDelegate changeContrastAndBright;
        public DeskewingWithAngleDelegate deskewingWithAngle;

        /// <summary>
        /// 私有构造函数，防止外部实例化。
        /// </summary>
        private CvLibInterop1(string dllPath)
        {
            LoadDll(dllPath);
        }

        /// <summary>
        /// Singleton 模式的实例属性。
        /// </summary>
        public static CvLibInterop1 Instance
        {
            get
            {
                if (_instance==null)
                {
                    Initialize();
                }
                return _instance;
            }
        }

        /// <summary>
        /// 初始化实例并加载 DLL。
        /// </summary>
        public static void Initialize()
        {
            if (_instance == null)
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        // 获取程序的根目录
                        string projectPath = AppDomain.CurrentDomain.BaseDirectory;
                        string tensorrtPath = Path.Combine(projectPath, @"windows-x64\imagedr-windows-x64-sdk-v1.2\windows-x64");
                        string cvlibPath = Path.Combine(tensorrtPath, "cvlib.dll");
                        _instance = new CvLibInterop1(cvlibPath);
                    }
                }
            }
        }

        private void LoadDll(string dllPath)
        {
            try
            {
                SetDllDirectory(Path.GetDirectoryName(dllPath));
                _dllHandle = LoadLibraryEx(dllPath, nint.Zero, LoadLibraryFlags.LOAD_WITH_ALTERED_SEARCH_PATH);
                if (_dllHandle == nint.Zero)
                {
                    int errorCode = Marshal.GetLastWin32Error();
                    throw new Exception($"Failed to load DLL: {dllPath}. Error code: {errorCode}");
                }

                // 加载函数指针
                initImageDrHander = GetDelegate<InitImageDrHanderDelegate>("initImageDrHander", CallingConvention.Cdecl);
                closeImageDrHandler = GetDelegate<CloseImageDrHandlerDelegate>("closeImageDrHandler", CallingConvention.Cdecl);
                skewAngle = GetDelegate<SkewAngleDelegate>("skewAngle", CallingConvention.Cdecl);
                deskewing = GetDelegate<DeskewingDelegate>("deskewing", CallingConvention.Cdecl);
                textImageOrientation = GetDelegate<TextImageOrientationDelegate>("textImageOrientation", CallingConvention.Cdecl);
                rotate = GetDelegate<RotateDelegate>("rotate", CallingConvention.Cdecl);
                //cleanup = GetDelegate<CleanupDelegate>("cleanup", CallingConvention.Cdecl);
                removeBlackEdges = GetDelegate<RemoveBlackEdgesDelegate>("removeBlackDdges", CallingConvention.Cdecl);
                setToWhite = GetDelegate<SetToWhiteDelegate>("setToWhite", CallingConvention.Cdecl);
                changeGamma = GetDelegate<ChangeGammaDelegate>("changeGamma", CallingConvention.Cdecl);
                changeContrastAndBright = GetDelegate<ChangeContrastAndBrightDelegate>("changeContrastAngBright", CallingConvention.Cdecl);
                deskewingWithAngle = GetDelegate<DeskewingWithAngleDelegate>("deskewingWithAngle", CallingConvention.Cdecl);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Dispose();
            }
        }

        /// <summary>
        /// 释放由 CvLibInterop 占用的所有资源。
        /// </summary>
        public void Dispose()
        {
            if (_dllHandle != nint.Zero)
            {
                FreeLibrary(_dllHandle);
                _dllHandle = nint.Zero;
            }
        }

        private T GetDelegate<T>(string functionName, CallingConvention callingConvention) where T : Delegate
        {
            nint procAddress = GetProcAddress(_dllHandle, functionName);
            if (procAddress == nint.Zero)
            {
                throw new Exception($"Failed to get address for function: {functionName}");
            }
            return (T)Marshal.GetDelegateForFunctionPointer(procAddress, typeof(T));
        }

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern nint LoadLibraryEx(string dllToLoad, nint hFile, LoadLibraryFlags dwFlags);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool FreeLibrary(nint hModule);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern nint GetProcAddress(nint hModule, string procedureName);

        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern bool SetDllDirectory(string lpPathName);

        [Flags]
        private enum LoadLibraryFlags : uint
        {
            DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
            LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
            LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
            LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
            LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
            LOAD_LIBRARY_SEARCH_APPLICATION_DIR = 0x00000200,
            LOAD_LIBRARY_SEARCH_DEFAULT_DIRS = 0x00001000,
            LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR = 0x00000100,
            LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800,
            LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400,
            LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
        }
    }
}